package com.concurrent.thread.service;

import com.concurrent.thread.dao.UserMapper;
import com.concurrent.thread.dao.UsersMapper;
import com.concurrent.thread.entity.User;
import com.concurrent.thread.entity.Users;
import com.concurrent.thread.util.MyExecutor;
import com.concurrent.thread.util.SqlSessionContext;
import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Service;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;

/**
 * @author Mr.yuan
 * @version v1.0
 * @date 2019/9/26 14:02
 **/
@Service
public class UserService {

    private final UserService1 userService1;
    private final UserService2 userService2;
    private final SqlSessionContext sqlSessionContext;

    public UserService(UserService1 userService1, UserService2 userService2, SqlSessionContext sqlSessionContext) {
        this.userService1 = userService1;
        this.userService2 = userService2;
        this.sqlSessionContext = sqlSessionContext;
    }

    public void batchAdd() throws Exception {

        // 构建对象信息
        List<User> list = new ArrayList<>();
        for (int j = 0; j < 1; j++) {
            list.add(buildUser(j));
        }
        List<Users> list2 = new ArrayList<>();
        for (int j = 0; j < 1; j++) {
            list2.add(buildUsers(j));
        }

        List<Callable<Integer>> callable = new ArrayList<>();

        // 获取数据库连接（内部创建了自有事务）
        SqlSession sqlSession = sqlSessionContext.getSqlSession();
        Connection connection = sqlSession.getConnection();
        // 设置手动提交
        connection.setAutoCommit(false);
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
        try {
            // 多线程调用
//            callable.add(()->userService1.call(user1,userMapper));
//            callable.add(()->userService2.call(user2,userMapper));

            callable.add(() -> new UserService3().call(list, userMapper));
            callable.add(() -> new UserService4().call(list2, usersMapper));
            List<Future<Integer>> futures = MyExecutor.getExecutor().invokeAll(callable);

            // 统计执行结果
            int num = 0;
            for (Future<Integer> future : futures) {
                num += future.get();
            }
            // 所有线程执行成功则=2，直接提交，否则回滚
            if (num == 2) {
                connection.commit();
            } else {
                connection.rollback();
            }
        } catch (Exception e) {
            e.printStackTrace();
            connection.rollback();
        } finally {
            connection.close();
        }
    }

    private User buildUser(int i) {
        return User.builder()
                .account(UUID.randomUUID().toString())
                .name("测试多线程事务")
                .address("济南市高新区汉峪金谷云顶天宫")
                .age(i)
                .birth(new Date())
                .mobile("121212")
                .build();
    }

    private Users buildUsers(int i) {
        return Users.builder()
                .account(UUID.randomUUID().toString())
                .name("测试多线程事务")
                .address("济南市高新区汉峪金谷云顶天宫")
                .age(i)
                .birth(new Date())
                .mobile("121212")
                .build();
    }

    private class UserService3 {
        Integer call(List<User> user, UserMapper userMapper) {
            try {
                userMapper.insertList(user);
                return 1;
            } catch (Exception e) {
                System.out.println(Thread.currentThread().getName() + "failure");
            }
            return 0;
        }
    }

    private class UserService4 {
        Integer call(List<Users> user, UsersMapper usersMapper) {
            try {
                usersMapper.insertList(user);
                return 1;
            } catch (Exception e) {
                System.out.println(Thread.currentThread().getName() + "failure");
            }
            return 0;
        }
    }

}
